home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
ivd2dvi
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
12KB
|
521 lines
/*
* Input/output routines for ivd2dvi. Copyright 1988 by Larry Denenberg.
* May be freely distributed as long as this notice is retained.
*
* Here are the naming conventions for input routines: A routine is named
* "Read..." if it merely reads something from standard input, e.g.
* /ReadByte/, /ReadSigned/. Recall that the input DVI file always
* comes via standard input. As in C, there are routines "FRead..."
* whose first argument is of type FILE*; these read from an arbitrary
* file and are used to read TFM files. We also have the "Copy..."
* routines; these are just like their "Read..." counterparts but also
* copy every byte read to the output DVI file. There are no "FCopy..."
* routines for obvious reasons. The routine /CopyNBytes/ has no "Read"
* analogue because it returns no value.
*/
#include <stdio.h>
#include "global.h"
#include "commands.h"
/* Procedure and global variable defined in auxiliary.c */
extern void BadDVIAbort();
extern font *CurFont;
/* Global variables defined in ivd2dvi.c */
extern int State;
extern char *ProgramName;
/* Global variables defined here */
unsigned BufSize = BUFDEFAULTSIZE; /* buffer size, mutable with -b */
unsigned_byte *Buffer; /* first char of input buffer */
unsigned_byte *BufEnd; /* pointer just beyond buffer area */
unsigned_byte *BufFirstNonchar; /* first unused spot; save input here */
unsigned_byte *BufPointer; /* pointer into buffer; read from here */
boolean ReadingCommand = FALSE; /* true iff reading a DVI main command */
unsigned_byte *VStack; /* start of nesting validation stack */
unsigned_byte *VEnd; /* pointer just beyond vstack area */
unsigned_byte *VPointer; /* vstack pointer to first unused slot */
long BytesOutput = 0L; /* number of bytes written to output */
/* Procedures defined in this file, in order of definition */
void InitIOBuffers();
unsigned_byte ReadByte();
void NestingValidate(), BufOverflow();
unsigned_byte ReadCommand(), CopyByte(), FReadByte();
void SkipNBytes(), FSkipNBytes(), CopyNBytes();
long ReadUnsigned(), FReadUnsigned(), ReadSigned(), FReadSigned();
long CopyWord(), CopyUnsigned();
unsigned_byte *ReadFilePosition();
void ResetFilePosition(), RereadLastByte();
void WriteByte(), WriteWord(), WriteNumber(), WriteString();
unsigned SignedBytes();
/*
* Initialize two of the three main memory areas in ivd2dvi. The
* size of each is a function of the value /BufSize/ which can be
* changed by the user with the -b flag. So the user doesn't need to
* know that there are lots of buffers with different sizes; if there's
* not enough room, using the -b flag will make them all bigger.
*/
void
InitIOBuffers()
{
Buffer = SEQALLOC(BufSize, unsigned_byte);
BufPointer = NULL;
BufFirstNonchar = Buffer;
BufEnd = Buffer + BufSize;
VStack = SEQALLOC(BufSize/SMALLBUFDIVISOR, unsigned_byte);
VPointer = VStack;
VEnd = VStack + BufSize/SMALLBUFDIVISOR;
if ((Buffer == NULL) || (VStack = NULL)) {
fprintf(stderr, "\n%s fatal error: can't allocate buffers\n",
ProgramName);
exit(3);
}
}
/*
* Read a byte from the input DVI file. All input routines that read
* standard input must come through here.
*
* The problem to worry about is that ivd2dvi frequently needs to reread
* input. Rather than doing seeks, we've (perhaps foolishly) decided to
* buffer input so we can see it again later. This means that ivd2dvi is
* a true filter, which is a useless advantage since TeX doesn't write
* its standard output and since most dvi drivers (dvi2ps in particular)
* need real files and can't read standard input.
*
* Now, we don't buffer *all* input, since we know that only if we're
* simulating will we need to reread the input. So anytime we're
* reading from the real input file and we're simulating, we save the
* character in the buffer.
*
* /BufPointer/ is the place in the buffer from which we're reading
* saved input. It also serves as a flag; if it's NULL, then we're not
* reading saved input at all. So the basic idea is: if /BufPointer/
* is pointing, return the character it points to and advance it.
* Otherwise, do a real read, and save if simulating.
*
* What if /BufPointer/ points, but there's no more input? Then we want
* to go back to reading real input: set /BufPointer/ to NULL and call
* ourselves recursively to force real input. We also take this
* opportunity to clear out the buffer and start over, a step which is
* justified only because we start rereading input only when we stop
* simulating (thus nobody can need the saved input anymore).
*
* Note that it's an error if standard input ever comes to EOF; we
* should have seen the postamble and quit. Finally, /ReadingCommand/
* is TRUE iff the byte is a command and not a parameter; in this case
* we check it with /NestingValidate/.
*/
unsigned_byte
ReadByte()
{
int nextchar;
if (BufPointer) {
if (BufPointer < BufFirstNonchar) return *BufPointer++;
else {
BufPointer = NULL;
BufFirstNonchar = Buffer;
return ReadByte();
}
} else {
nextchar = getchar();
if (nextchar == EOF) BadDVIAbort("unexpected EOF");
if (ReadingCommand) NestingValidate((unsigned_byte) nextchar);
if (State >= SIMULATING) {
*BufFirstNonchar++ = (unsigned_byte) nextchar;
if (BufFirstNonchar > BufEnd) BufOverflow();
}
return nextchar;
}
}
/*
* Test a character for nesting. Since dvitype doesn't check DVI-IVD
* files for validity, it's important to do careful checking here---
* ivd2dvi will get horribly confused if reflections and pushes don't
* nest properly. This routine gets called to validate every single
* command read from the input file. The method is simple: if the
* command is PUSH, BEG_REFLECT, or BOP, just push it on the stack (the
* stack is the tiny /VStack/, not used for anything else). If the
* command is POP, END_REFLECT, or EOP, pop a command from the stack and
* be sure it matches. Ignore all other commands.
*/
void
NestingValidate(nextchar)
unsigned_byte nextchar;
{
switch (nextchar) {
case PUSH: case BEG_REFLECT: case BOP:
if (VPointer >= VEnd) BufOverflow(); else *VPointer++ = nextchar;
break;
case POP:
if ((VPointer <= VStack) || (*--VPointer != PUSH))
BadDVIAbort("reflection commands incorrectly nested");
break;
case EOP:
if ((VPointer <= VStack) || (*--VPointer != BOP))
BadDVIAbort("reflection commands incorrectly nested");
break;
case END_REFLECT:
if ((VPointer <= VStack) || (*--VPointer != BEG_REFLECT))
BadDVIAbort("reflection commands incorrectly nested");
break;
}
}
/*
* As Knuth would say, ``Exit due to finiteness.'' We can become less
* finite, but we have to know in advance!
*/
void
BufOverflow()
{
fprintf(stderr, "\n%s: Buffer size %d was inadequate\n",
ProgramName, BufSize);
fprintf(stderr, "(Use the -b flag to increase the buffer size)\n");
exit(3);
}
/*
* Read a command. Just read a byte with /ReadingCommand/ turned on
* (and then turn it off!). See the discussion of /VStack/ above.
*/
unsigned_byte
ReadCommand()
{
unsigned_byte result;
ReadingCommand = TRUE;
result = ReadByte();
ReadingCommand = FALSE;
return result;
}
/*
* Copy a single byte from the input DVI file to the output file and
* return it.
*/
unsigned_byte
CopyByte()
{
unsigned result = ReadByte();
WriteByte(result);
return result;
}
/*
* Read a byte from the input file /fp/. We don't have to worry about
* buffering or special checks, just about EOF. The error message is
* justified because we do input only from the TFM file of the current
* font (except for the main input DVI file, of course).
*/
unsigned_byte
FReadByte(fp)
FILE *fp;
{
int nextchar;
nextchar = getc(fp);
if (nextchar == EOF) {
fprintf(stderr, "\n%s: unexpected EOF in TFM file for font %s\n",
ProgramName, CurFont->name);
exit(2);
}
return nextchar;
}
/*
* Discard /n/ bytes from the input DVI file.
*/
void
SkipNBytes(n)
long n;
{
while (n--) (void) ReadByte();
}
/*
* Discard /n/ bytes from the input file /fp/.
*/
void
FSkipNBytes(fp,n)
FILE *fp;
long n;
{
while (n--) (void) FReadByte(fp);
}
/*
* Copy /n/ bytes from the input DVI file to the output file.
*/
void
CopyNBytes(n)
long n;
{
while (n--) WriteByte(ReadByte());
}
/*
* Read an unsigned integer of length /bytes/ from the input DVI file.
*/
long
ReadUnsigned(bytes)
unsigned bytes;
{
long result = 0;
while (bytes-- != 0) {
result <<= 8;
result |= ReadByte();
}
return result;
}
/*
* Read an unsigned integer of length /bytes/ from the input file /fp/.
*/
long
FReadUnsigned(fp,bytes)
FILE *fp;
unsigned bytes;
{
long result = 0;
while (bytes--) {
result <<= 8;
result |= FReadByte(fp);
}
return result;
}
/*
* Read a signed integer of length /bytes/ from the input DVI file.
* This must be done with no assumptions about the length of long ints
* on the machine and without using sign-extending right shifts.
*/
long
ReadSigned(bytes)
unsigned bytes;
{
long result;
result = ReadByte();
if (result >= 128) result -= 256;
while (--bytes) {
result <<= 8;
result |= ReadByte();
}
return result;
}
/*
* Read a signed integer of length /bytes/ from the input file /fp/.
*/
long
FReadSigned(fp,bytes)
FILE *fp;
int bytes;
{
long result;
result = FReadByte(fp);
if (result >= 128) result -= 256;
while (--bytes) {
result <<= 8;
result |= FReadByte(fp);
}
return result;
}
/*
* Copy a 32-bit word from the input DVI file to the output file, and
* return it.
*/
long
CopyWord()
{
long result = ReadSigned(4);
WriteWord(result);
return result;
}
/*
* Copy an unsigned integer of length /bytes/ from the input DVI file
* to the output file, and return it.
*/
long
CopyUnsigned(bytes)
unsigned bytes;
{
long result = ReadUnsigned(bytes);
WriteNumber(result,bytes);
return result;
}
/*
* Get a file position from which we can take input later. If we're
* currently taking input from the buffer, the result is just the buffer
* pointer. If not, the saved position is the place inside the buffer
* where we're storing the input as it comes in. Details at /ReadByte/.
*/
unsigned_byte *
ReadFilePosition()
{
if (BufPointer) return BufPointer; else return BufFirstNonchar;
}
/*
* Reset to take input starting from a saved file position. Easy.
*/
void
ResetFilePosition(position)
unsigned_byte *position;
{
BufPointer = position;
}
/*
* Arrange to see the last character of the input again. Possible only
* when we're reading buffered input, in which case it's simple. In
* fact, this routine is used only by /SetString/ while RTYPESETTING.
*/
void RereadLastByte() {
if (!BufPointer || (BufPointer == Buffer)) {
fprintf(stderr, "\n%s internal error: illegal attempt to backup input\n",
ProgramName);
exit(4);
}
BufPointer--;
}
/*
* Write a single byte to the output DVI file. All non-diagnostic output
* ***MUST*** go through this routine so that the number of bytes output
* is counted accurately.
*/
void
WriteByte(value)
unsigned value;
{
putchar(value);
BytesOutput++;
}
/*
* Write a 32-bit word to the output file.
*/
void
WriteWord(value)
long value;
{
WriteNumber(value, 4);
}
/*
* Write /value/ to the output file as an integer of length /bytes/.
*/
void
WriteNumber(value,bytes)
long value;
unsigned bytes;
{
if (bytes > 1) WriteNumber(value >> 8, bytes - 1);
WriteByte((unsigned_byte) value & 0377);
}
/*
* Write a string to the output DVI file.
*/
void
WriteString(string)
char *string;
{
char *pchar;
for (pchar = string; *pchar; pchar++)
WriteByte((unsigned_byte) *pchar);
}
/*
* Calculate how many bytes are required to represent /number/. Don't
* say /number = -(number+1)/ because of the possibility of overflow.
*/
unsigned
SignedBytes(number)
long number;
{
if (number > 0) { number = -number; number -= 1; }
if (number >= -128) return 1;
else if (number >= -(128*256)) return 2;
else if (number >= -(128*256*256)) return 3;
else return 4;
}